#include <linux/init.h>             
#include <linux/module.h>           
#include <linux/kernel.h>
#include <linux/kthread.h>      
#include <linux/delay.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/gpio.h>

/*
#include <linux/kobject.h>

struct kobj_attribute {
    struct attribute attr;
    ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
            char *buf);
    ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
             const char *buf, size_t count);
};

#define __ATTR(_name,_mode,_show,_store) { \
    .attr = {.name = __stringify(_name), .mode = _mode },   \
    .show   = _show,                    \
    .store  = _store,                   \
}
static struct kobject *kob;

extern struct kobject * __must_check kobject_create_and_add(const char *name,
						struct kobject *parent);

#include <linux/sysfs.h>
int __must_check sysfs_create_files(struct kobject *kobj,
				   const struct attribute * const *attr);

retval = sysfs_create_files(&obj->kobj,(const struct attribute **)my_attrs);
if (retval) {
    // ...
}

*/

static ssize_t my_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
    return sprintf(buf, "test show\n");
}

static ssize_t my_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
    char t_buf[513];
    if (count > 512)
        count = 512;
    memcpy(t_buf, buf, count);
    t_buf[count] = 0;
    printk("%s\n", t_buf);
    return count;
}

//Doesn't support 0666 in new version.
static struct kobj_attribute my_attr = __ATTR(echo, 0660, my_show, my_store); 
static struct kobj_attribute null_attr = __ATTR(null_test, 0660, NULL, NULL); 
static struct kobj_attribute ro_attr = __ATTR(ro_test, 0660, my_show, NULL); 
static struct attribute *my_attrs[] = {
    &my_attr.attr,
    &null_attr.attr,
    &ro_attr.attr,
    NULL,
};

static struct kobject *kob;

static int __init sys_test_init(void)
{
    int ret;
    // 创建并添加一个kobj节点，将会在/sys目录下创建一个test_kobj目录
    kob = kobject_create_and_add("test_kobj", kernel_kobj->parent);
    if (!kob)
    {
        printk("??? kobject_create_and_add\n");
    }

    // 添加属性，根据每一个属性名在test_kobj目录下创建一个相同的文件，并提供读写借口
    ret = sysfs_create_files(kob, (const struct attribute **)my_attrs);
    if (ret){
        printk("sys create files faild?? code [%d]\n", ret);
    }

    printk(KERN_DEBUG "kobj test\n");
    return 0;
}

static void __exit sys_test_exit(void)
{
    kobject_put(kob);
    printk(KERN_DEBUG "byebye\n");
}

module_init(sys_test_init);
module_exit(sys_test_exit);

MODULE_AUTHOR("test@xx.com>");
MODULE_DESCRIPTION("Linux Kernel hello module");
MODULE_LICENSE("GPL");
